package chans

import (
	"fmt"
	"time"
)

/**
 * 通道内数据结构
 * @property time time.Time 通道数据推送时间
 * @property data any 通道数据
 */
type ChanData struct {
	Time time.Time
	Data any
}

// 通道消费函数类型
type IConsume interface {
	Done(data *ChanData)
}

// 通道消费函数类型
type FuncConsume func(data *ChanData)

// 实现 IConsume 接口
func (f FuncConsume) Done(data *ChanData) { f(data) }

// 通道结构
type Chan struct {
	// 通道标识， 主要用于日志记录
	ID string
	// 通道缓冲个数
	ChanSize int16
	// 消费函数, 优先与消费接口
	FuncConsume FuncConsume
	// 消费接口
	Consume IConsume
	// 数据通道
	pipe chan *ChanData
}

// 关闭通道
func (c *Chan) Close() {
	if c.pipe != nil {
		close(c.pipe)
	}
}

// 向通道推送数据
func (c *Chan) Append(data any) {
	if c.pipe != nil {
		c.pipe <- &ChanData{
			Time: time.Now(),
			Data: data,
		}
	}
}

// 启动: 循环处理通道数据
func (c *Chan) Run() error {
	// 初始化通道
	if c.ChanSize > 0 {
		c.pipe = make(chan *ChanData, c.ChanSize)
	} else {
		c.pipe = make(chan *ChanData)
	}

	// 统一可执行回调到接口上
	if c.FuncConsume != nil {
		c.Consume = FuncConsume(c.FuncConsume)
	} else if c.Consume == nil {
		return fmt.Errorf("%s not set execute callback", c.ID)
	}

	// 开启协程， 在协程中消费通道数据
	go func() {
		// 读取通道
		for data := range c.pipe {
			c.Consume.Done(data)
		}
	}()

	return nil
}

/**
 * 通道组件配置数据结构
 */
type Conf struct {
	ID          string      // 通道标识， 主要用于日志记录
	ChanSize    int16       // 通道缓冲个数
	FuncConsume FuncConsume // 消费函数, 优先与消费接口
	Consume     IConsume    // 消费接口
}

/**
 * 创建通道
 * @param conf *Conf 通道配置
 * @return *Chan 通道
 */
func New(conf *Conf) *Chan {
	ch := &Chan{
		ID:          conf.ID,
		ChanSize:    conf.ChanSize,
		FuncConsume: conf.FuncConsume,
		Consume:     conf.Consume,
	}
	ch.Run() // 启动通道
	return ch
}
